/*************************************************
 *	dOpSys Week-3
 *	Nikolas Bram & Dennis Thomasen
 *	20104278     & 20103903 
 *	Linked list implementation for the
 *	consumer-producer exercise
 *
 *************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>

#include "producer-consumer-list.h"

/*Returning a list - assigning start values to the list properties*/
struct list *new_list(void)
{
  struct list *l; //Create new instance of the list

  l = (struct list *)malloc(sizeof(struct list)); //Allocating space for the list
  l->length = 0; //Initially setting the length to 0
  //Making the first element = the last element and allocating memory
  l->first = l->last = (struct node *)malloc(sizeof(struct node));
  //Assigning NULL to the first element and the next
  l->first->elm = NULL;
  l->first->next = NULL;
  
  pthread_mutex_t mutex;
  pthread_mutex_init(&mutex,NULL); //The mutex is created, NULL gives the mutex default attributes
  l->lock = mutex; //The lock is assigned to the list

  return l; //Returning the newly created list
}

/*Recieving a list and a node - putting an element into the list*/
void add_list(struct list *l, struct node *n) {
	pthread_mutex_lock(&l->lock); //acquiring the lock
	l->last = l->last->next = n; //adding node n to the list as the last element
	l->length++; //Incrementing the length to match the newly put element
	printf("inserting, #%d\n", l -> length); //print statement to keep track of input/output of list
	pthread_mutex_unlock(&l->lock); //releasing lock
}

/*Recieving a list*/
void remove_list(struct list *l) {
	while(l->length==0); //While there's still elements in the list
	pthread_mutex_lock(&l->lock); //Acquirring the lock
	printf("removing, #%d\n", l -> length);
	if(l->length > 0) { //If there's items in the list
		l->first = l->first->next; //setting the first object as the next
		l->length--; //Subtracting the length of the list
	}
	pthread_mutex_unlock(&l->lock); //Releasing the lock again
}

/*Returning a node - creating a new node*/
struct node *new_node(void)
{
  struct node *n; //Instanciating a new node

  n = (struct node *)malloc(sizeof(struct node)); //allocating memory
  n->elm = NULL; //sets the element to NULL
  n->next = NULL; //Sets the next element to NULL

  return n; //Return the newly created node
}

/*Returning a node and recieving a char - make new node structure in which str is a pointer to new copy of string s*/
struct node *new_node_str(char *s)
{
  struct node *n;

  n = (struct node *)malloc(sizeof(struct node)); //Allocating memory
  n->elm = (void *)malloc((strlen(s)+1) * sizeof(char)); //allocating memory
  strcpy((char *)n->elm, s); //Copy string s into n->elm
  n->next = NULL; //Set the next element to NULL

  return n; //Returning the newly created node
}
